Note
Go to the end to download the full example code.
Remove and Add Elements¶
Author: @WJinger
Import some packages¶
from collections import namedtuple
from typing import Any, Union
import matplotlib.pyplot as plt
import numpy as np
import openseespy.opensees as ops
import opstool as opst
import opstool.vis.plotly as opsplt
Set base variables¶
# Set unit
UNIT = opst.pre.UnitSystem(length="m", force="kn", time="sec")
# Set constant
g = 9.80665 * (UNIT.m / UNIT.sec**2)
Ubig = 1.0e10
Usmall = 1.0e-10
# Set data path
# data_path = "./OutData"
# os.makedirs(data_path, exist_ok=True)
# opst.post.set_odb_path(data_path) # set opstool ODB path
Section creator function¶
def secCreate(sec_name: str, secTag: int, matTag: int, w: float, h: float, info: bool = True) -> dict[str, Any]:
"""
# Just for a simple rectangle section
:param sec_name: section name
:param secTag: section tag
:param matTag: material tag
:param w: width
:param h: height
:param info: if True, print section information
:return: a dictionary with the section properties
"""
# section outline
sec_outline = [[0, 0], [w, 0], [w, h], [0, h]]
inner_geo = opst.pre.section.create_polygon_patch(sec_outline)
SEC = opst.pre.section.FiberSecMesh(sec_name=sec_name)
SEC.add_patch_group({"inner": inner_geo})
SEC.set_ops_mat_tag({"inner": matTag})
SEC.set_mesh_size({"inner": (w + h) / 20.0})
SEC.set_mesh_color({"inner": "lightblue"})
SEC.mesh()
# section properties
SEC.centring()
sec_props = SEC.get_frame_props(display_results=info) # print section properties
if info:
SEC.view(fill=True, show_legend=True, aspect_ratio="equal")
plt.show()
# define section
SEC.to_opspy_cmds(secTag=secTag, G=100 * UNIT.gpa)
return sec_props
Model creator function¶
Values for return
RETURN_VAL = namedtuple(
"RETURN_VAL",
["ctrl_node", "remove_ele", "add_ele", "top_link_ele", "base_link_ele"],
)
"""
Remove element:
ops.remove('ele', RETURN_VAL.remove_ele)
Add element:
ops.element(*RETURN_VAL.add_ele)
"""
Model creater function
def triangleStruc(top_free: bool = False, base_free: bool = False, info: bool = True) -> RETURN_VAL:
"""
# Create a simple triangle structure
:param top_free: if True, add zeroLength element to the top
:param base_free: if True, add zeroLengthSection element to the base
:param info: if True, print section element information
:return a namedtuple with the following values:
- :ctrl_node: the control node for static analysis
- :remove_ele: the element to be removed
- :add_ele: the element to be added
- :top_link_ele: the top zeroLength element
- :base_link_ele: the base zeroLengthSection element
"""
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
# Initialize
ops.wipe()
ops.model("basic", "-ndm", 3, "-ndf", 6)
# For vertical element
transf_ver = 1
ops.geomTransf("PDelta", transf_ver, *(-1, 0, 0))
# For other element
transf_other = 2
ops.geomTransf("PDelta", transf_other, *(0, 0, 1))
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
# Steel material
steelTag = 10
ops.uniaxialMaterial("Steel02", steelTag, 400 * UNIT.mpa, 206 * UNIT.gpa, 0.01)
# Elastic no tension material
ENTTag = 20
ops.uniaxialMaterial("ENT", ENTTag, 200 * UNIT.gpa)
# Elastic material
elasticTag = 30
ops.uniaxialMaterial("Elastic", elasticTag, 1.0e6)
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
# Define vertical element section
secTag_1 = 1
W_1 = 10.0 * UNIT.cm
H_1 = 10.0 * UNIT.cm
sec_props_1 = secCreate(sec_name="vertical", secTag=secTag_1, matTag=steelTag, w=W_1, h=H_1, info=info)
# Define vertical base link element section
secTag_2 = 2
sec_props_2 = secCreate(
sec_name="vertical base",
secTag=secTag_2,
matTag=ENTTag,
w=W_1,
h=H_1,
info=info,
)
# Define other element section
secTag_3 = 3
W_2 = 2.0 * UNIT.cm
H_2 = 2.0 * UNIT.cm
sec_props_3 = secCreate(sec_name="oblique", secTag=secTag_3, matTag=steelTag, w=W_2, h=H_2, info=info)
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
# Node Tags
nodeTag_base = 1
nodeTag_top = 2
nodeTag_base_link = 3 # Base link node
nodeTag_top_link = 4 # Top link node
nodeTag_left_base = 5
nodeTag_right_base = 6
# Element Tags
eleTag_main = 1
eleTag_left = 2
eleTag_right = 3
eleTag_base_link = 4 # Base link element
eleTag_top_link = 5 # Top link element
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
# Create nodes
ops.node(nodeTag_base, 0.0, 0.0, 0.0)
ops.node(nodeTag_top, 0.0, 0.0, 1.0 * UNIT.m)
ops.node(nodeTag_left_base, 0.0, -1.0 * UNIT.m, 0.0)
ops.node(nodeTag_right_base, 0.0, 1.0 * UNIT.m, 0.0)
# Nodes fix
ops.fix(nodeTag_base, 1, 1, 1, 1, 1, 1)
ops.fix(nodeTag_left_base, 1, 1, 1, 1, 1, 1)
ops.fix(nodeTag_right_base, 1, 1, 1, 1, 1, 1)
# Integration
npTag_1 = 1
npTag_2 = 2
ops.beamIntegration("Legendre", npTag_1, secTag_1, 5)
ops.beamIntegration("Legendre", npTag_2, secTag_3, 5)
"# ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- ----- -----"
"""
Note:
In order to check the local axes of zeroLength and zeroLengthSection, the length of zeroLength and zeroLengthSection elements is not zero.
It causes opensees warning but does not affect the results.
"""
if top_free and not base_free:
print("CASE: zeroLength")
ops.node(nodeTag_top_link, 0.0, 0.0, 1.2 * UNIT.m) # For top zeroLength
ops.element(
"dispBeamColumn",
eleTag_main,
*(nodeTag_top, nodeTag_base),
transf_ver,
npTag_1,
) # Single vertical element
ops.element(
"dispBeamColumn",
eleTag_left,
*(nodeTag_top, nodeTag_left_base),
transf_ver,
npTag_2,
) # Left oblique element
mats = (elasticTag, elasticTag, elasticTag, elasticTag, elasticTag, elasticTag)
ops.element(
"zeroLength",
eleTag_top_link,
*(nodeTag_top_link, nodeTag_top),
"-mat",
*mats,
"-dir",
*(1, 2, 3, 4, 5, 6),
"-orient",
*(0, 0, -1),
*(0, -1, 0),
)
return_val = RETURN_VAL(
ctrl_node=nodeTag_top_link,
remove_ele=eleTag_left,
add_ele=(
"dispBeamColumn",
eleTag_right,
*(nodeTag_top, nodeTag_right_base),
transf_ver,
npTag_2,
),
top_link_ele=eleTag_top_link,
base_link_ele=None,
)
elif not top_free and base_free:
print("CASE: zeroLengthSection")
ops.node(nodeTag_base_link, 0.0, 0.0, 0.2 * UNIT.m) # For base zeroLengthSection
ops.element(
"dispBeamColumn",
eleTag_main,
*(nodeTag_top, nodeTag_base_link),
transf_ver,
npTag_1,
) # Single vertical element
ops.element(
"dispBeamColumn",
eleTag_left,
*(nodeTag_top, nodeTag_left_base),
transf_ver,
npTag_2,
) # Left oblique element
ops.equalDOF(*(nodeTag_base, nodeTag_base_link), *(1, 2, 3))
ops.element(
"zeroLengthSection",
eleTag_base_link,
*(nodeTag_base_link, nodeTag_base),
secTag_2,
"-orient",
*(0, 0, -1),
*(0, -1, 0),
)
return_val = RETURN_VAL(
ctrl_node=nodeTag_top,
remove_ele=eleTag_left,
add_ele=(
"dispBeamColumn",
eleTag_right,
*(nodeTag_top, nodeTag_right_base),
transf_ver,
npTag_2,
),
top_link_ele=None,
base_link_ele=eleTag_base_link,
)
elif top_free and base_free:
print("CASE: zeroLength & zeroLengthSection")
ops.node(nodeTag_top_link, 0.0, 0.0, 1.2 * UNIT.m) # For top zeroLength
ops.node(nodeTag_base_link, 0.0, 0.0, 0.2 * UNIT.m) # For base zeroLengthSection
ops.element(
"dispBeamColumn",
eleTag_main,
*(nodeTag_top, nodeTag_base_link),
transf_ver,
npTag_1,
) # Single vertical element
ops.element(
"dispBeamColumn",
eleTag_left,
*(nodeTag_top, nodeTag_left_base),
transf_ver,
npTag_2,
) # Left oblique element
mats = (elasticTag, elasticTag, elasticTag, elasticTag, elasticTag, elasticTag)
ops.element(
"zeroLength",
eleTag_top_link,
*(nodeTag_top_link, nodeTag_top),
"-mat",
*mats,
"-dir",
*(1, 2, 3, 4, 5, 6),
"-orient",
*(0, 0, -1),
*(0, -1, 0),
)
ops.equalDOF(*(nodeTag_base, nodeTag_base_link), *(1, 2, 3))
ops.element(
"zeroLengthSection",
eleTag_base_link,
*(nodeTag_base_link, nodeTag_base),
secTag_2,
"-orient",
*(0, 0, -1),
*(0, -1, 0),
)
return_val = RETURN_VAL(
ctrl_node=nodeTag_top_link,
remove_ele=eleTag_left,
add_ele=(
"dispBeamColumn",
eleTag_right,
*(nodeTag_top, nodeTag_right_base),
transf_ver,
npTag_2,
),
top_link_ele=eleTag_top_link,
base_link_ele=eleTag_base_link,
)
else:
print("CASE: None")
ops.element(
"dispBeamColumn",
eleTag_main,
*(nodeTag_top, nodeTag_base),
transf_ver,
npTag_1,
) # Single vertical element
ops.element(
"dispBeamColumn",
eleTag_left,
*(nodeTag_top, nodeTag_left_base),
transf_ver,
npTag_2,
) # Left oblique element
return_val = RETURN_VAL(
ctrl_node=nodeTag_top,
remove_ele=eleTag_left,
add_ele=(
"dispBeamColumn",
eleTag_right,
*(nodeTag_top, nodeTag_right_base),
transf_ver,
npTag_2,
),
top_link_ele=None,
base_link_ele=None,
)
return return_val
Analysis function¶
def analysisLib(
targets: Union[list, tuple, np.ndarray],
patternTag: int,
ctrl_node: int,
ODB: opst.post.CreateODB,
) -> tuple[np.ndarray, np.ndarray]:
"""
# Static analysis function
:param targets: Displacement path
:param patternTag: Pattern tag
:param ctrl_node: Control node tag
:param ODB: CreateODB object
:return: Displacement and force
"""
ops.system("BandGeneral")
ops.constraints("Transformation")
ops.numberer("RCM")
analysis = opst.anlys.SmartAnalyze("Static")
segs = analysis.static_split(targets=targets, maxStep=0.01 * UNIT.m)
force_lambda: Union[list, float] = [0.0]
node_disp: Union[list, float] = [0.0]
for seg in segs:
ok = analysis.StaticAnalyze(node=ctrl_node, dof=2, seg=seg) # node tag 1, dof 2
if ok < 0:
raise RuntimeError("Analysis failed") # noqa: TRY003
# Fetch response
ODB.fetch_response_step()
force_lambda.append(ops.getLoadFactor(patternTag))
node_disp.append(ops.nodeDisp(ctrl_node, 2))
return np.array(node_disp), np.array(force_lambda)
Check single column hysteretic curve¶
For Case 1, I just want to look at the hysteresis curve with only vertical element.
# Case
CASE_1 = 1
# Create model
model_info = triangleStruc(top_free=True, base_free=True, info=True)
OPSTOOL :: The section vertical has been successfully meshed!
Frame Section Properties
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Symbol ┃ Value ┃ Definition ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ A │ 1.000E-02 │ Cross-sectional area │
│ centroid │ (0.000E+00, 0.000E+00) │ Elastic centroid │
│ Iy │ 8.333E-06 │ Moment of inertia y-axis │
│ Iz │ 8.333E-06 │ Moment of inertia z-axis │
│ Iyz │ 0.000E+00 │ Product of inertia │
│ Wyt │ 1.667E-04 │ Section moduli of top fibres y-axis │
│ Wyb │ 1.667E-04 │ Section moduli of bottom fibres y-axis │
│ Wzt │ 1.667E-04 │ Section moduli of top fibres z-axis │
│ Wzb │ 1.667E-04 │ Section moduli of bottom fibres z-axis │
│ J │ 1.406E-05 │ Torsion constant │
│ phi │ 0.000E+00 │ Principal axis angle │
│ rho_rebar │ 0.000E+00 │ Ratio of reinforcement │
└───────────┴────────────────────────┴────────────────────────────────────────┘
OPSTOOL :: The section vertical base has been successfully meshed!
Frame Section Properties
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Symbol ┃ Value ┃ Definition ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ A │ 1.000E-02 │ Cross-sectional area │
│ centroid │ (0.000E+00, 0.000E+00) │ Elastic centroid │
│ Iy │ 8.333E-06 │ Moment of inertia y-axis │
│ Iz │ 8.333E-06 │ Moment of inertia z-axis │
│ Iyz │ 0.000E+00 │ Product of inertia │
│ Wyt │ 1.667E-04 │ Section moduli of top fibres y-axis │
│ Wyb │ 1.667E-04 │ Section moduli of bottom fibres y-axis │
│ Wzt │ 1.667E-04 │ Section moduli of top fibres z-axis │
│ Wzb │ 1.667E-04 │ Section moduli of bottom fibres z-axis │
│ J │ 1.406E-05 │ Torsion constant │
│ phi │ 0.000E+00 │ Principal axis angle │
│ rho_rebar │ 0.000E+00 │ Ratio of reinforcement │
└───────────┴────────────────────────┴────────────────────────────────────────┘
OPSTOOL :: The section oblique has been successfully meshed!
Frame Section Properties
┏━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━┳━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┓
┃ Symbol ┃ Value ┃ Definition ┃
┡━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━╇━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━━┩
│ A │ 4.000E-04 │ Cross-sectional area │
│ centroid │ (0.000E+00, 0.000E+00) │ Elastic centroid │
│ Iy │ 1.333E-08 │ Moment of inertia y-axis │
│ Iz │ 1.333E-08 │ Moment of inertia z-axis │
│ Iyz │ -5.294E-23 │ Product of inertia │
│ Wyt │ 1.333E-06 │ Section moduli of top fibres y-axis │
│ Wyb │ 1.333E-06 │ Section moduli of bottom fibres y-axis │
│ Wzt │ 1.333E-06 │ Section moduli of top fibres z-axis │
│ Wzb │ 1.333E-06 │ Section moduli of bottom fibres z-axis │
│ J │ 2.249E-08 │ Torsion constant │
│ phi │ 0.000E+00 │ Principal axis angle │
│ rho_rebar │ 0.000E+00 │ Ratio of reinforcement │
└───────────┴────────────────────────┴────────────────────────────────────────┘
CASE: zeroLength & zeroLengthSection
WARNING ZeroLength::setDomain(): Element 5 has L= 0.2, which is greater than the tolerance
ZeroLengthSection::setDomain() -- Element 4has L= 0.2, which is greater than the tolerance
Remove oblique element
ops.remove("ele", model_info.remove_ele)
# Create data base
ODB = opst.post.CreateODB(odb_tag=CASE_1, save_fiber_sec_resp=True, fiber_ele_tags=[1, 2, 3, 4], model_update=True)
# Linear timeSeries
ts = 1
ops.timeSeries("Linear", ts)
Pattern for static analysis
pattern = 100
ops.pattern("Plain", pattern, ts)
ops.load(model_info.ctrl_node, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
Displacement path
disp_path = (
np.array([
0.0,
0.05,
-0.05,
0.10,
-0.10,
0.15,
-0.15,
0.20,
-0.20,
0.25,
-0.25,
0.30,
-0.30,
0.0,
])
* UNIT.m
)
Analysis
disp, force = analysisLib(targets=disp_path, patternTag=pattern, ctrl_node=model_info.ctrl_node, ODB=ODB)
# Save data base
ODB.save_response(zlib=True)
🚀 OPSTOOL::SmartAnalyze: 0%| | 0/420 [00:00<?, ? step/s]
🚀 OPSTOOL::SmartAnalyze: 5%|██▋ | 22/420 [00:00<00:01, 210.76 step/s]
🚀 OPSTOOL::SmartAnalyze: 10%|█████▎ | 44/420 [00:00<00:01, 208.88 step/s]
🚀 OPSTOOL::SmartAnalyze: 15%|███████▉ | 65/420 [00:00<00:01, 205.56 step/s]
🚀 OPSTOOL::SmartAnalyze: 20%|██████████▍ | 86/420 [00:00<00:01, 193.90 step/s]
🚀 OPSTOOL::SmartAnalyze: 25%|████████████▌ | 106/420 [00:00<00:01, 185.36 step/s]
🚀 OPSTOOL::SmartAnalyze: 30%|██████████████▉ | 125/420 [00:00<00:01, 177.68 step/s]
🚀 OPSTOOL::SmartAnalyze: 34%|█████████████████ | 143/420 [00:00<00:01, 172.61 step/s]
🚀 OPSTOOL::SmartAnalyze: 38%|███████████████████▏ | 161/420 [00:00<00:01, 167.48 step/s]
🚀 OPSTOOL::SmartAnalyze: 43%|█████████████████████▌ | 181/420 [00:00<00:01, 175.77 step/s]
🚀 OPSTOOL::SmartAnalyze: 48%|███████████████████████▉ | 201/420 [00:01<00:01, 182.55 step/s]
🚀 OPSTOOL::SmartAnalyze: 53%|██████████████████████████▎ | 221/420 [00:01<00:01, 185.44 step/s]
🚀 OPSTOOL::SmartAnalyze: 57%|████████████████████████████▌ | 240/420 [00:01<00:00, 182.31 step/s]
🚀 OPSTOOL::SmartAnalyze: 62%|██████████████████████████████▊ | 259/420 [00:01<00:01, 139.56 step/s]
🚀 OPSTOOL::SmartAnalyze: 66%|█████████████████████████████████ | 278/420 [00:01<00:00, 150.90 step/s]
🚀 OPSTOOL::SmartAnalyze: 71%|███████████████████████████████████▎ | 297/420 [00:01<00:00, 159.18 step/s]
🚀 OPSTOOL::SmartAnalyze: 75%|█████████████████████████████████████▌ | 316/420 [00:01<00:00, 167.25 step/s]
🚀 OPSTOOL::SmartAnalyze: 80%|███████████████████████████████████████▉ | 335/420 [00:01<00:00, 172.63 step/s]
🚀 OPSTOOL::SmartAnalyze: 84%|██████████████████████████████████████████ | 353/420 [00:02<00:00, 173.95 step/s]
🚀 OPSTOOL::SmartAnalyze: 89%|████████████████████████████████████████████▎ | 372/420 [00:02<00:00, 177.29 step/s]
🚀 OPSTOOL::SmartAnalyze: 93%|██████████████████████████████████████████████▋ | 392/420 [00:02<00:00, 181.52 step/s]
🚀 OPSTOOL::SmartAnalyze: 98%|████████████████████████████████████████████████▉ | 411/420 [00:02<00:00, 182.90 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 420/420 [00:02<00:00, 182.90 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 420/420 [00:02<00:00, 176.27 step/s]
Note: OpenSees LogFile has been generated in .SmartAnalyze-OpenSees.log.
>>> 🎉 OPSTOOL::SmartAnalyze:: Successfully finished! Time consumption: 2.384 s. 🎉
OPSTOOL :: All responses data with _odb_tag = 1 saved in G:\opstool\docs\.opstool.output/RespStepData-1.nc!
View results
plt.close("all")
plt.title("Single Column Hysteretic Curve")
plt.plot(disp, force, linewidth=1.0, label="Single Column", zorder=2)
plt.xlim(-0.4, 0.4)
plt.ylim(-500 * UNIT.kn, 500 * UNIT.kn)
plt.xlabel("Displacement (m)")
plt.ylabel("Force (kN)")
plt.legend(loc="lower right", bbox_to_anchor=(1.0, 0.0))
plt.grid(linestyle="--", linewidth=0.5, zorder=1)
plt.show()

Visualize model response
fig = opsplt.plot_nodal_responses_animation(odb_tag=CASE_1, resp_type="disp", show_undeformed=True)
fig
# fig.show()
OPSTOOL :: Loading response data from G:\opstool\docs\.opstool.output/RespStepData-1.nc ...
Remove and add element during analysis¶
# Case
CASE_2 = 2
"""Ok, For case 2 I want to remove and add element during analysis."""
# Create model
model_info = triangleStruc(top_free=True, base_free=True, info=False)
# Create data base
ODB = opst.post.CreateODB(odb_tag=CASE_2, fiber_ele_tags="ALL", model_update=True)
# Linear timeSeries
ts = 1
ops.timeSeries("Linear", ts)
# Pattern for static analysis
pattern_1 = 100
ops.pattern("Plain", pattern_1, ts)
ops.load(model_info.ctrl_node, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
# Displacement path
disp_path_1 = (
np.array([
0.0,
0.05,
-0.05,
0.10,
-0.10,
0.15,
-0.15,
# 0.20, -0.20,
# 0.25, -0.25,
# 0.30, -0.30,
0.0,
])
* UNIT.m
)
# Analysis
disp_1, force_1 = analysisLib(targets=disp_path_1, patternTag=pattern_1, ctrl_node=model_info.ctrl_node, ODB=ODB)
OPSTOOL :: The section vertical has been successfully meshed!
OPSTOOL :: The section vertical base has been successfully meshed!
OPSTOOL :: The section oblique has been successfully meshed!
CASE: zeroLength & zeroLengthSection
🚀 OPSTOOL::SmartAnalyze: 0%| | 0/120 [00:00<?, ? step/s]
🚀 OPSTOOL::SmartAnalyze: 12%|██████▍ | 15/120 [00:00<00:00, 145.72 step/s]
🚀 OPSTOOL::SmartAnalyze: 26%|█████████████▏ | 31/120 [00:00<00:00, 152.16 step/s]
🚀 OPSTOOL::SmartAnalyze: 39%|███████████████████▉ | 47/120 [00:00<00:00, 154.00 step/s]
🚀 OPSTOOL::SmartAnalyze: 52%|██████████████████████████▊ | 63/120 [00:00<00:00, 155.04 step/s]
🚀 OPSTOOL::SmartAnalyze: 66%|█████████████████████████████████▌ | 79/120 [00:00<00:00, 153.16 step/s]
🚀 OPSTOOL::SmartAnalyze: 79%|████████████████████████████████████████▍ | 95/120 [00:00<00:00, 152.16 step/s]
🚀 OPSTOOL::SmartAnalyze: 92%|██████████████████████████████████████████████▎ | 111/120 [00:00<00:00, 151.57 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 120/120 [00:00<00:00, 151.57 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 120/120 [00:00<00:00, 153.21 step/s]
Note: OpenSees LogFile has been generated in .SmartAnalyze-OpenSees.log.
>>> 🎉 OPSTOOL::SmartAnalyze:: Successfully finished! Time consumption: 0.784 s. 🎉
Remove element
ops.loadConst("-time", 0.0) # Important !!!
ops.remove("ele", model_info.remove_ele) # Remove element
# Pattern for static analysis (After remove element)
pattern_2 = 200
ops.pattern("Plain", pattern_2, ts)
ops.load(model_info.ctrl_node, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
# Displacement path (After remove element)
disp_path_2 = (
np.array([
0.0,
# 0.05, -0.05,
# 0.10, -0.10,
# 0.15, -0.15,
0.20,
-0.20,
0.25,
-0.25,
0.30,
-0.30,
0.0,
])
* UNIT.m
)
# Analysis (After remove element)
disp_2, force_2 = analysisLib(targets=disp_path_2, patternTag=pattern_2, ctrl_node=model_info.ctrl_node, ODB=ODB)
🚀 OPSTOOL::SmartAnalyze: 0%| | 0/300 [00:00<?, ? step/s]
🚀 OPSTOOL::SmartAnalyze: 7%|███▌ | 21/300 [00:00<00:01, 201.96 step/s]
🚀 OPSTOOL::SmartAnalyze: 14%|███████▏ | 42/300 [00:00<00:01, 194.39 step/s]
🚀 OPSTOOL::SmartAnalyze: 21%|██████████▌ | 62/300 [00:00<00:01, 194.01 step/s]
🚀 OPSTOOL::SmartAnalyze: 27%|█████████████▉ | 82/300 [00:00<00:01, 193.17 step/s]
🚀 OPSTOOL::SmartAnalyze: 34%|█████████████████ | 102/300 [00:00<00:01, 194.77 step/s]
🚀 OPSTOOL::SmartAnalyze: 41%|████████████████████▎ | 122/300 [00:00<00:00, 192.66 step/s]
🚀 OPSTOOL::SmartAnalyze: 47%|███████████████████████▋ | 142/300 [00:00<00:00, 193.93 step/s]
🚀 OPSTOOL::SmartAnalyze: 54%|███████████████████████████ | 162/300 [00:00<00:00, 144.37 step/s]
🚀 OPSTOOL::SmartAnalyze: 60%|█████████████████████████████▊ | 179/300 [00:01<00:00, 150.50 step/s]
🚀 OPSTOOL::SmartAnalyze: 66%|█████████████████████████████████▏ | 199/300 [00:01<00:00, 163.23 step/s]
🚀 OPSTOOL::SmartAnalyze: 72%|████████████████████████████████████▏ | 217/300 [00:01<00:00, 166.75 step/s]
🚀 OPSTOOL::SmartAnalyze: 78%|███████████████████████████████████████▏ | 235/300 [00:01<00:00, 169.93 step/s]
🚀 OPSTOOL::SmartAnalyze: 85%|██████████████████████████████████████████▎ | 254/300 [00:01<00:00, 174.63 step/s]
🚀 OPSTOOL::SmartAnalyze: 92%|█████████████████████████████████████████████▊ | 275/300 [00:01<00:00, 183.30 step/s]
🚀 OPSTOOL::SmartAnalyze: 98%|█████████████████████████████████████████████████▏| 295/300 [00:01<00:00, 188.05 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 300/300 [00:01<00:00, 188.05 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 300/300 [00:01<00:00, 178.62 step/s]
Note: OpenSees LogFile has been generated in .SmartAnalyze-OpenSees.log.
>>> 🎉 OPSTOOL::SmartAnalyze:: Successfully finished! Time consumption: 1.680 s. 🎉
Add element
ops.loadConst("-time", 0.0) # Important !!!
ops.element(*model_info.add_ele) # Add element
# Pattern for static analysis (After add element)
pattern_3 = 300
ops.pattern("Plain", pattern_3, ts)
ops.load(model_info.ctrl_node, 0.0, 1.0, 0.0, 0.0, 0.0, 0.0)
# Displacement path (After add element)
disp_path_3 = (
np.array([
0.0,
0.05,
-0.05,
0.10,
-0.10,
0.15,
-0.15,
0.20,
-0.20,
0.25,
-0.25,
0.30,
-0.30,
0.0,
])
* UNIT.m
)
# Analysis (After add element)
disp_3, force_3 = analysisLib(targets=disp_path_3, patternTag=pattern_3, ctrl_node=model_info.ctrl_node, ODB=ODB)
🚀 OPSTOOL::SmartAnalyze: 0%| | 0/420 [00:00<?, ? step/s]
🚀 OPSTOOL::SmartAnalyze: 3%|█▋ | 14/420 [00:00<00:03, 131.54 step/s]
🚀 OPSTOOL::SmartAnalyze: 7%|███▋ | 30/420 [00:00<00:02, 147.07 step/s]
🚀 OPSTOOL::SmartAnalyze: 11%|█████▌ | 46/420 [00:00<00:02, 149.84 step/s]
🚀 OPSTOOL::SmartAnalyze: 15%|███████▋ | 63/420 [00:00<00:02, 152.66 step/s]
🚀 OPSTOOL::SmartAnalyze: 19%|█████████▌ | 79/420 [00:00<00:02, 152.23 step/s]
🚀 OPSTOOL::SmartAnalyze: 23%|███████████▋ | 96/420 [00:00<00:02, 155.48 step/s]
🚀 OPSTOOL::SmartAnalyze: 27%|█████████████▎ | 112/420 [00:00<00:02, 153.63 step/s]
🚀 OPSTOOL::SmartAnalyze: 30%|███████████████▏ | 128/420 [00:00<00:01, 154.10 step/s]
🚀 OPSTOOL::SmartAnalyze: 34%|█████████████████▏ | 144/420 [00:00<00:01, 150.25 step/s]
🚀 OPSTOOL::SmartAnalyze: 38%|███████████████████ | 160/420 [00:01<00:01, 149.10 step/s]
🚀 OPSTOOL::SmartAnalyze: 42%|████████████████████▉ | 176/420 [00:01<00:01, 150.85 step/s]
🚀 OPSTOOL::SmartAnalyze: 46%|██████████████████████▊ | 192/420 [00:01<00:01, 149.27 step/s]
🚀 OPSTOOL::SmartAnalyze: 50%|████████████████████████▊ | 208/420 [00:01<00:01, 151.58 step/s]
🚀 OPSTOOL::SmartAnalyze: 53%|██████████████████████████▋ | 224/420 [00:01<00:01, 151.46 step/s]
🚀 OPSTOOL::SmartAnalyze: 57%|████████████████████████████▌ | 240/420 [00:01<00:01, 112.41 step/s]
🚀 OPSTOOL::SmartAnalyze: 61%|██████████████████████████████▍ | 256/420 [00:01<00:01, 122.87 step/s]
🚀 OPSTOOL::SmartAnalyze: 65%|████████████████████████████████▌ | 273/420 [00:01<00:01, 133.66 step/s]
🚀 OPSTOOL::SmartAnalyze: 69%|██████████████████████████████████▍ | 289/420 [00:02<00:00, 139.33 step/s]
🚀 OPSTOOL::SmartAnalyze: 73%|████████████████████████████████████▎ | 305/420 [00:02<00:00, 143.49 step/s]
🚀 OPSTOOL::SmartAnalyze: 76%|██████████████████████████████████████▏ | 321/420 [00:02<00:00, 145.98 step/s]
🚀 OPSTOOL::SmartAnalyze: 80%|████████████████████████████████████████ | 337/420 [00:02<00:00, 143.66 step/s]
🚀 OPSTOOL::SmartAnalyze: 84%|█████████████████████████████████████████▉ | 352/420 [00:02<00:00, 145.12 step/s]
🚀 OPSTOOL::SmartAnalyze: 87%|███████████████████████████████████████████▋ | 367/420 [00:02<00:00, 142.48 step/s]
🚀 OPSTOOL::SmartAnalyze: 91%|█████████████████████████████████████████████▋ | 384/420 [00:02<00:00, 148.15 step/s]
🚀 OPSTOOL::SmartAnalyze: 95%|███████████████████████████████████████████████▌ | 400/420 [00:02<00:00, 149.55 step/s]
🚀 OPSTOOL::SmartAnalyze: 99%|█████████████████████████████████████████████████▌| 416/420 [00:02<00:00, 148.80 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 420/420 [00:02<00:00, 148.80 step/s]
🚀 OPSTOOL::SmartAnalyze: 100%|██████████████████████████████████████████████████| 420/420 [00:02<00:00, 144.96 step/s]
Note: OpenSees LogFile has been generated in .SmartAnalyze-OpenSees.log.
>>> 🎉 OPSTOOL::SmartAnalyze:: Successfully finished! Time consumption: 2.898 s. 🎉
Save data base
ODB.save_response(zlib=True)
OPSTOOL :: All responses data with _odb_tag = 2 saved in G:\opstool\docs\.opstool.output/RespStepData-2.nc!
View results (After remove element) sphinx_gallery_thumbnail_number = 6
plt.close("all")
plt.title("Triangle Remove Element Hysteretic Curve")
plt.plot(
disp,
force,
label="Single Column",
color="gray",
linewidth=1.5,
linestyle="--",
zorder=2,
)
plt.plot(disp_1, force_1, linewidth=1.0, label="Before Remove", zorder=3)
plt.plot(disp_2, force_2 + force_1[-1], linewidth=1.0, label="After Remove", zorder=3)
plt.xlim(-0.4, 0.4)
plt.ylim(-500 * UNIT.kn, 500 * UNIT.kn)
plt.xlabel("Displacement (m)")
plt.ylabel("Force (kN)")
plt.legend(loc="lower right", bbox_to_anchor=(1.0, 0.0))
plt.grid(linestyle="--", linewidth=0.5, zorder=1)
plt.show()

View results (After add element)
plt.close("all")
plt.title("Demaged Single Column Add Element Hysteretic Curve")
plt.plot(
disp,
force,
label="Single Column",
color="gray",
linewidth=1.5,
linestyle="--",
zorder=2,
)
plt.plot(
disp_3,
force_3 + force_1[-1] + force_2[-1],
linewidth=1.0,
label="After Add",
zorder=3,
)
plt.xlim(-0.4, 0.4)
plt.ylim(-500 * UNIT.kn, 500 * UNIT.kn)
plt.xlabel("Displacement (m)")
plt.ylabel("Force (kN)")
plt.legend(loc="lower right", bbox_to_anchor=(1.0, 0.0))
plt.grid(linestyle="--", linewidth=0.5, zorder=1)
plt.show()

Visualize model responses
fig = opsplt.plot_nodal_responses_animation(odb_tag=CASE_2, resp_type="disp", show_undeformed=True)
fig
# fig.show()
OPSTOOL :: Loading response data from G:\opstool\docs\.opstool.output/RespStepData-2.nc ...
Visualize final model (Case 2)
opsplt.set_plot_props(point_size=5, line_width=3)
fig = opsplt.plot_model(
show_ele_numbering=True,
show_local_axes=True,
)
fig
# fig.show()
Check zeroLength element
ODB_ele_Link = opst.post.get_element_responses(odb_tag=CASE_2, ele_type="Link", print_info=False)
print(f"ODB_ele_link.eleTags: {ODB_ele_Link.eleTags.values}")
# Check zeroLengthSection element
ODB_ele_sec = opst.post.get_element_responses(odb_tag=CASE_2, ele_type="FiberSection", print_info=False)
print(f"ODB_ele_sec.eleTags: {ODB_ele_sec.eleTags.values}")
ODB_ele_link.eleTags: [4 5]
ODB_ele_sec.eleTags: [1 2 3 4]
print(ODB_ele_sec.data_vars)
Data variables:
Stresses (time, eleTags, secPoints, fiberPoints) float32 22MB 0.0 ... nan
Strains (time, eleTags, secPoints, fiberPoints) float32 22MB 0.0 ... nan
secForce (time, eleTags, secPoints, DOFs) float32 269kB 0.0 0.0 ... nan nan
secDefo (time, eleTags, secPoints, DOFs) float32 269kB 0.0 -0.0 ... nan
ys (eleTags, secPoints, fiberPoints) float64 53kB 0.02253 ... nan
zs (eleTags, secPoints, fiberPoints) float64 53kB 0.002494 ... nan
areas (eleTags, secPoints, fiberPoints) float64 53kB 4.339e-05 ... nan
matTags (eleTags, secPoints, fiberPoints) float32 26kB 10.0 10.0 ... nan
print(ODB_ele_sec.data_vars["ys"])
<xarray.DataArray 'ys' (eleTags: 4, secPoints: 5, fiberPoints: 329)> Size: 53kB
array([[[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan],
[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan],
[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan],
[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan],
[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan]],
[[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
...
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534],
[-0.00894108, -0.00788283, -0.00798224, ..., 0.00123532,
0.00951401, 0.00795534]],
[[ 0.02253355, -0.0359375 , -0.04575958, ..., nan,
nan, nan],
[ nan, nan, nan, ..., nan,
nan, nan],
[ nan, nan, nan, ..., nan,
nan, nan],
[ nan, nan, nan, ..., nan,
nan, nan],
[ nan, nan, nan, ..., nan,
nan, nan]]])
Coordinates:
* eleTags (eleTags) int32 16B 1 2 3 4
* secPoints (secPoints) int32 20B 1 2 3 4 5
* fiberPoints (fiberPoints) int32 1kB 1 2 3 4 5 6 ... 324 325 326 327 328 329
Total running time of the script: (0 minutes 21.142 seconds)


